package cn.demoncat.util.lang.entity.thread;

import cn.demoncat.util.lang.ThreadUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 循环线程（控制器）
 *
 * @author 延晓磊
 * @since 2021年02月23日
 */
public class LoopThread {

    /**
     * 是否停止所有线程
     *
     * static：
     * 所有实例（不针对线程）共享一个主内存的数据，即保证变量的唯一性（在主内存中是唯一的变量）。
     *
     * volatile：
     * 所有线程都读取主存中的数据，因此保证了变量的一致性（多线程的可见性）。
     * 线程执行时，会开启自己的工作内存（私有），同时将主存数据拷贝到自己的工作内存，以后读数据都是针对自己的工作内存中的数据（写时会同步，但是有延时），所以会造成不一致。
     * 使用volatile修饰后，多线程将直接读取主存中的数据（不再读取工作内存的变量），即多线程读取的是同一个数据，因此保证了数据的一致性（多线程的可见性）.
     */
    private static volatile boolean stopAll;

    /**
     * 是否停止线程
     */
    private volatile boolean stop;
    /**
     * 每次循环执行后的休眠秒数
     */
    private int executeSleepSeconds;
    /**
     * 每次抛异常后的休眠秒数
     */
    private int exceptionSleepSeconds;
    /**
     * 线程名称
     */
    private String name;

    private static final Logger LOG = LoggerFactory.getLogger(LoopThread.class);

    /**
     * 创建（并启动）循环线程
     *
     * @param name                  线程名称
     * @param executeSleepSeconds   每次循环执行后的休眠秒数
     * @param exceptionSleepSeconds 每次抛异常后的休眠秒数
     * @param runnable              执行任务
     *
     * @return 循环线程控制器
     *
     * @author 延晓磊
     * @since 2021年02月23日
     */
    public static LoopThread build(String name, int executeSleepSeconds, int exceptionSleepSeconds, Runnable runnable){
        // 创建循环线程（控制器）
        LoopThread loop = new LoopThread();
        loop.stop = false;
        loop.name = name;
        loop.executeSleepSeconds = executeSleepSeconds;
        loop.exceptionSleepSeconds = exceptionSleepSeconds;
        // 创建线程
        Thread thread = new Thread(() ->{
            LOG.info("循环线程【" + name + "】开始执行");
            // 无限循环
            while (!isStopAll() && !loop.isStop()){
               try {
                   // 执行任务
                   runnable.run();
               }catch (Exception e){
                   LOG.error("循环线程【" + name + "】执行异常", e);
                   // 异常休眠
                   if (loop.exceptionSleepSeconds > 0) {
                       ThreadUtil.sleep(loop.exceptionSleepSeconds);
                   }
               }
               // 执行休眠
                if (loop.executeSleepSeconds > 0) {
                    ThreadUtil.sleep(loop.executeSleepSeconds);
                }
            }
            LOG.info("循环线程【" + name + "】终止执行");
        }, name);
        // 设置为守护线程，随应用停止
        thread.setDaemon(true);
        // 启动
        thread.start();
        // 返回控制器（由外部控制循环终止）
        return loop;
    }

    public static boolean isStopAll() {
        return stopAll;
    }

    /**
     * 停止所有线程
     *
     * 注：建议声明 @PreDestroy 执行本方法，在系统关闭时停止所有循环线程
     */
    public static void stopAll() {
        LoopThread.stopAll = true;
    }

    public boolean isStop() {
        return stop;
    }

    /**
     * 停止线程
     */
    public void stop() {
        this.stop = true;
    }

    public int getExecuteSleepSeconds() {
        return executeSleepSeconds;
    }

    /**
     * 每次循环执行后的休眠秒数
     *
     * @param executeSleepSeconds
     */
    public void setExecuteSleepSeconds(int executeSleepSeconds) {
        this.executeSleepSeconds = executeSleepSeconds;
    }

    public int getExceptionSleepSeconds() {
        return exceptionSleepSeconds;
    }

    /**
     * 每次抛异常后的休眠秒数
     *
     * @param exceptionSleepSeconds
     */
    public void setExceptionSleepSeconds(int exceptionSleepSeconds) {
        this.exceptionSleepSeconds = exceptionSleepSeconds;
    }

    public String getName() {
        return name;
    }

}
